#ifndef cope_queue_cc
#define cope_queue_cc

#include "cope-queue.h"
#include <iostream>
#include <iomanip>

COPEPriQueue::COPEPriQueue() {        
  
    dsr_ = 0; //to indicate DSR protocol or not
    cope_vir_table_ = new VirQueue(); 
    prq_qh_.setIFQ(this);
    // qh_.setIFQ(*this);
}

COPEPriQueue::~COPEPriQueue() { 
   
}
//COPEPriQueue::initVirTable()
int COPEPriQueue::command(int argc, const char*const* argv) {
    Tcl& tcl = Tcl::instance();
    if(argc == 3) {
	if(strcmp(argv[1], "cope-init") == 0) {
	    if (strcmp(argv[2], "DSR") == 0) {
		dsr_ = 1; // IS A DSR	
	    } else {
		dsr_ = 0; // NON-DSR	
	    }
	    return (TCL_OK);

	} else {
	    TclObject *obj;
		
	    if( (obj = TclObject::lookup(argv[2])) == 0) {
		fprintf(stderr, "%s lookup failed\n", argv[1]);
		return TCL_ERROR;
	    }
	    if (strcmp(argv[1], "up-target") == 0) {
		if (*argv[2] == '0') {
		    up_target_ = 0;
		    return (TCL_OK);
		}
		up_target_ = (NsObject*) obj;
		if (up_target_ == 0) {
		    tcl.resultf("no such object %s", argv[2]);
		    return (TCL_ERROR);
		}
		return (TCL_OK);
	    }
	    if (strcmp(argv[1], "down-target") == 0) {
		if (*argv[2] == '0') {
		    down_target_ = 0;
		    return (TCL_OK);
		}
		down_target_ = (NsObject*) obj;
		if (down_target_ == 0) {
		    tcl.resultf("no such object %s", argv[2]);
		    return (TCL_ERROR);
		}
	    }
	}
    }

    if(dsr_) {
	return CMUPriQueue::command(argc, argv);
    } else {
	return PriQueue::command(argc, argv);
    }
   
}
void COPEPriQueue::setCOPEHandler(COPEHandler * h_cope) {
 
    h_cope_ = h_cope;
  
}
int COPEPriQueue::prq_assign_queue(Packet *p)
{
    if(HDR_COPE(p)->ctype_ != COPE_DATA)
	return IFQ_RTPROTO;
    
    struct hdr_cmn *ch = HDR_CMN(p);    
    switch(ch->ptype()) {
    case PT_AODV:
    case PT_DSR:
    case PT_IMEP:
    case PT_MESSAGE:	/* used by DSDV */
    case PT_TORA:
	return IFQ_RTPROTO;

    case PT_AUDIO:
    case PT_VIDEO:
	return IFQ_REALTIME;

	// case PT_ACK:
	// 	return IFQ_LOWDELAY;

    default:
	return IFQ_NORMAL;
    }
}
void COPEPriQueue::showQueue(COPE* cope_inst)
{

    Packet * it;
    int len = 0;
    for(int q = 0; q < IFQ_MAX; q++) {
	if(prq_snd_[q].ifq_len > 0) {
	    len += prq_snd_[q].ifq_len;
	    it = prq_snd_[q].ifq_head;
	    
	    while(it != NULL) {
		//cope_inst->qout
		cout << setw(10) << Scheduler::instance().clock()
				<< setw(8) << HDR_CMN(it)->uid_
				<< setw(8) << HDR_TCP(it)->seqno()
				<< setw(8) << HDR_CMN(it)->cope_pkt_id() 
				<< setw(8) << HDR_CMN(it)->next_hop();
		if(HDR_CMN(it)->ptype() == PT_ACK)
		    //cope_inst->qout
		    cout << setw(8) << "ack" << endl;
		else if(HDR_COPE(it)->ctype_ == COPE_RETX)
		    //cope_inst->qout
		    cout << setw(8) << "crx" << endl;
		else
		    //cope_inst->qout
		    cout<< endl;
		it = it->next_;
	    }
	}
    }
    //cope_inst->qout << endl;
    cout << endl;
    //	cout << "Length is " << len ;
    //	std::cout << std::endl;
}
/*
 * This is called by cope_prq_senddown or recvHigh/NormalPriority
 */
void COPEPriQueue::cope_enqueue(Packet *p, bool rt, COPE * cope_inst) {
    //    cope_inst->ctrl_pkt_timer_.stop();
    if(dsr_) {      //DSR
	/* get the rank of queue and fetch the corresponding ifq */
        int q = prq_assign_queue(p);
        struct ifqueue *ifq = &prq_snd_[q];
	// if(cope_inst->node_->nodeid() == 7) {
	// cout << "-----before enqueue------" << endl;
	// showQueue(cope_inst);
	// cope_vir_table_->show();
	// }
		    
        /* drop the packet if ifq is full */
        if(IF_QFULL(ifq)) {
	    // cope_inst->qout << "------------------FULL------------------" << endl;
	    // showQueue(cope_inst);
            IF_DROP(ifq);
	    CMUPriQueue::drop(p, DROP_IFQ_QFULL);
            return;
        }

	if(HDR_IP(p)->saddr() == cope_inst->node_->address()) {
	    if(HDR_COPE(p)->ctype_ == COPE_DATA) 
		cope_inst->set_pkt_header(p);
	}

	// if(cope_inst->node_->nodeid() == 7)
	//     cope_vir_table_->show();
	
	cope_vir_table_->enque_vir_pkt(p, rt); // insert packet to virQueue

	// if(cope_inst->node_->nodeid() == 7)
	//     cope_vir_table_->show();

	 
	// in pool the packet
	if(HDR_COPE(p)->ctype_ == COPE_DATA)
	    cope_inst->pkt_pool_->in_pool(p);         

	// if(cope_inst->node_->nodeid() == 7)
	//     cope_vir_table_->show();
	    
        /* 
         * push back the packet into the queue, if it is an retransmission 
         * packet, put it to head of queue 
         */
        if(rt) {
	    IF_ENQUEUE_HEAD(ifq, p);
        } else { 
	    IF_ENQUEUE(ifq, p);
        }

	// cout << "------after enqueue------" << endl;
	// showQueue(cope_inst);
	// cope_vir_table_->show();
	
    } else {      //NON-DSR
	/* 
	 * push back the packet into the queue, if it is an retransmission 
	 * packet or high priority packet , put it to head of queue 
	 */
	if(rt) {
	    q_->enqueHead(p);  //PacketQueue's enqueHead
	    if (q_->length() >= qlim_) {
		Packet *to_drop = q_->lookup(q_->length()-1);
		q_->remove(to_drop);
		PriQueue::drop(to_drop);
	    }
	} else { 
	    enque(p);  //DropTail's enque
	}

    }
}
/*
 * dequeue an item from output queue, this is called by cope, when a packet
 * in output queue is encoded, it will call cope_vir_dequeue to synchronize
 * virtual queue
 */
Packet * COPEPriQueue::cope_dequeue_item(Packet * p) {
    
    /*
     * the return packet, it is not necessary, since no packet data xor
     * operation happen, just simulate 
     */
    Packet *res = NULL;

    if(dsr_) { // DSR protocol, use CMUPriQueue
	int q;
	for(q = 0; q < IFQ_MAX; q++) {
	    if(prq_snd_[q].ifq_len > 0) {
		//		IF_DEQUE_ITEM(&prq_snd_[q], Packet, p, res);
		Packet * iter =  prq_snd_[q].ifq_head;		
		Packet * prev_iter = iter;				
		while( iter != NULL ) {	
		    if(HDR_CMN(iter)->uid_ == HDR_CMN(p)->uid_) {		
			if(iter == prq_snd_[q].ifq_head) {		
			    IF_DEQUEUE(&prq_snd_[q], res);			
			} else if(iter == prq_snd_[q].ifq_tail) {		
			    res = prq_snd_[q].ifq_tail;			
			    prq_snd_[q].ifq_tail = prev_iter;	
			    prev_iter->next_ = 0;
			    prq_snd_[q].ifq_len --;
			} else {					
			    prev_iter->next_ = iter->next_;		
			    iter->next_ = 0;				
			    res = iter;
			    prq_snd_[q].ifq_len --;				
			}			    
			break;				
		    }	
		    prev_iter = iter;				
		    iter = iter->next_;
		}
	    


		if(res != NULL)
		    break;
	    }
	}
    } else { //Non-DSR protocol     
	q_->remove(p);  // remove a specific packet from packet queue
    }
    // showQueue();
    //    cope_vir_table_->remove_vir_pkt(p);  // synchronize the virtual queue
    //showQueue();
    return res;
}

/*
 * called by cope_resume
 */
void COPEPriQueue::cope_prq_resume(COPE * cope_inst) {

   
    if(dsr_) { //DSR
	Packet *p;
	assert(prq_blocked_);
#if PRIQUEUE_DEBUG > 0
	prq_validate();
#endif
	bool empty = true;
	p = prq_dequeue(&empty);

	if (p != 0) {
	    // if(empty)
	    // 	cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
	    stat_send_++;
	    if( HDR_CMN(p)->ptype() != PT_CBR
		&& HDR_CMN(p)->ptype() != PT_ACK
		&& HDR_CMN(p)->ptype()!=PT_TCP) {
		CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);
		return;
	    }
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;
	    // cout << "----------------resume-----------"
	    // 	 << HDR_CMN(max_size_pkt)->size() << endl;
	    int encoded = 0;
	    double timeout;
	    /*
	     * Use original packet p here, since we just simulate the xor operation
	     * and no further use for p, otherwise send_pkt should be a copy of p
	     */  	    

	    
	    /* cope encode downside packet */

	    if(HDR_CMN(p)->next_hop() >= 0 && HDR_COPE(p)->ctype_ != COPE_CTRL) {
		cope_vir_table_->remove_vir_pkt(p);  // synchronize the virtual queue
	        encoded = cope_prq_encode(p, cope_inst, &send_pkt, &max_size_pkt);
	    }

	    //	    showQueue();

	    if(encoded) {
	    // 	if(cope_inst->node_->nodeid() == 5)
	    // 	    cout << "resume " << HDR_CMN(send_pkt)->uid_
	    // 		 << " " << HDR_TCP(send_pkt)->seqno() << endl;
	    	// switch(HDR_CMN(p)->ptype()) {
	    	// case PT_TCP:
	    	//     cout << CUR_TIME << " TCP: node " << cope_inst->node_->nodeid() 
	    	// 	 << " cope ENCODE resume down packet " 
	    	// 	 << HDR_CMN(send_pkt)->cope_pkt_id()
	    	// 	 << " " << HDR_CMN(send_pkt)->uid_
	    	// 	 << " " << HDR_TCP(send_pkt)->seqno_
	    	// 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
	    	//   break;
	    	// case PT_ACK:
	    	//     cout << CUR_TIME << " ACK: node " << cope_inst->node_->nodeid() 
	    	// 	 << " cope ENCODE resume down packet " 
	    	// 	 << HDR_CMN(send_pkt)->cope_pkt_id()
	    	// 	 << " " << HDR_CMN(send_pkt)->uid_
	    	// 	 << " " << HDR_TCP(send_pkt)->seqno_
	    	// 	 << " " << HDR_TCP(send_pkt)->ackno() 
	    	// 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
	    	//   break;
	    	// case PT_CBR:
	    	//   cout << CUR_TIME <<" CBR: node " << cope_inst->node_->nodeid() 
	    	// 	 << " cope ENCODE send down packet " 
	    	// 	 << HDR_CMN(send_pkt)->cope_pkt_id()
	    	// 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
	    	// default:
	    	//   cout << CUR_TIME <<" Ctrl: node " << cope_inst->node_->nodeid() 
	    	// 	 << " cope ENCODE send down packet " 
	    	// 	 << HDR_CMN(send_pkt)->cope_pkt_id()
	    	// 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
	    	// }
		// cout << "original pkt size is " << HDR_CMN(p)->cope_pkt_id() 
		//      << " " << HDR_CMN(p)->size() << endl;
		// cout << "max_size is " << HDR_CMN(max_size_pkt)->cope_pkt_id() 
		//      << " "<< HDR_CMN(max_size_pkt)->size() << endl;
		// cout << "send out packet size is " <<HDR_CMN(send_pkt)->cope_pkt_id() 
		//      << " "<< HDR_CMN(send_pkt)->size() << endl;

		timeout = cope_inst->txtime(max_size_pkt);
		CMUPriQueue::target_->recv(send_pkt, (Handler*)&prq_qh_);
	    } else {
		// if(cope_inst->node_->nodeid() == 7) {
		//     cout << "resume " << HDR_CMN(send_pkt)->uid_
		// 	 << " " << HDR_TCP(send_pkt)->seqno() << endl;
		//     showQueue(cope_inst);
		// }
		
		// switch(HDR_CMN(p)->ptype()) {
		// case PT_TCP:
		// 	cout << CUR_TIME << " TCP: node " << cope_inst->node_->nodeid() 
		// 	     << " cope NATIVE resume down packet " 
		// 	     << HDR_CMN(p)->cope_pkt_id()
		// 	     << " " << HDR_CMN(p)->uid_
		// 	     << " " << HDR_TCP(p)->seqno_
		// 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		// 	break;
		// case PT_ACK:
		// 	cout << CUR_TIME << " ACK: node " << cope_inst->node_->nodeid() 
		// 	     << " cope NATIVE resume down packet " 
		// 	     << HDR_CMN(p)->cope_pkt_id()
		// 	     << " " << HDR_CMN(p)->uid_
		// 	     << " " << HDR_TCP(p)->seqno_
		// 	     << " " << HDR_TCP(p)->ackno() 
		// 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		// 	break;
		// case PT_CBR:
		// 	cout << CUR_TIME <<" CBR: node " << cope_inst->node_->nodeid() 
		// 	     << " cope NATIVE send down packet " 
		// 	     << HDR_CMN(p)->cope_pkt_id()
		// 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		// default:
		// 	cout << CUR_TIME <<" Ctrl: node " << cope_inst->node_->nodeid() 
		// 	     << " cope NATIVE send down packet " 
		// 	     << HDR_CMN(p)->cope_pkt_id()
		// 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		// }
		Packet::free(send_pkt);	
		CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);
	    }

	    if(encoded) {
	     
		/* send an encoded packet, should set the timer */
		cope_inst->start_timer(send_pkt, timeout);
	    }  /* else send a native packet, no need for timer */
	} else {  
	    prq_blocked_ = 0;
	}

    } else {  // NON-DSR

	double now = Scheduler::instance().clock();
	Packet* p = deque();
	// if(length() == 0)
	//     cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
	if(p)
	    cope_vir_table_->remove_vir_pkt(p);

	if (p != 0) {
	    /*
	     * Use original packet p here, since we just simulate the xor operation and 
	     * no further use for p, otherwise send_pkt should be a copy of p
	     */    
	    // Packet * send_pkt = p;
	    // int encoded = 0;
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;
	    int encoded = 0;
	    double timeout;
	    /* cope encode downside packet */
	    if( HDR_COPE(p)->ctype_ != COPE_CTRL ) 
		encoded = cope_prq_encode(p,cope_inst,&send_pkt, &max_size_pkt);
	    /* send out */
	    PriQueue::target_->recv(send_pkt, (QueueHandler*)(&cope_inst->h_cope_));

	    if(encoded) {
	        timeout = cope_inst->txtime(max_size_pkt);
	        /* send an encoded packet, should set the timer */
	        cope_inst->start_timer(send_pkt, timeout);	       
	    }  /* else send a native packet, no need for timer */ 

	} else {
	    if (unblock_on_resume_) {
		utilUpdate(last_change_, now, blocked_);
		last_change_ = now;
		blocked_ = 0;

	    } else {
		utilUpdate(last_change_, now, blocked_);
		last_change_ = now;
		blocked_ = 1;
	    }
	}
    }

}

Packet* COPEPriQueue::prq_dequeue(bool* empty) {
 
    Packet *p = NULL;
    int q;
    
    for(q = 0; q < IFQ_MAX; q++) {
	if(prq_snd_[q].ifq_len > 0) {
	    IF_DEQUEUE(&prq_snd_[q], p);
	    break;
	}
    }

    //    IF_EMPTY(&prq_snd_[IFQ_MAX-1], *empty);
    
    // Packet * it;
    // if (p)
    //   std::cout <<"dequed packet is "<< HDR_CMN(p)->uid_ 
    // 		<<  " " << HDR_CMN(p)->cope_pkt_id() 
    // 		<< " " << HDR_CMN(p)->next_hop()<< std::endl;
    // std::cout << "after deque :" << std::endl; 
    // for(q = 0; q < IFQ_MAX; q++) {
    // 	if(prq_snd_[q].ifq_len > 0) {
    // 	  it = prq_snd_[q].ifq_head;
    // 	  while(it != NULL) {
    // 	     std::cout << HDR_CMN(it)->uid_ 
    // 		       <<  " " << HDR_CMN(p)->cope_pkt_id() 
    // 		       << " " << HDR_CMN(it)->next_hop()<< "| ";
    // 	    it = it->next_;
    // 	  }
    // 	}
    // }
    // std::cout << std::endl;
  
    return p;
}

/* 
 * put the packet into output queue, and deque the head packet,
 * sent it down to mac layer
 */
void COPEPriQueue::cope_prq_senddown(Packet * p, COPE * cope_inst) {    
  
    if(dsr_) {   // dsr protocol, use CMUPriQueue
      
#if PRIQUEUE_DEBUG > 0
        prq_validate();
#endif       
        stat_recv_++;  //update state
      
        if(prq_blocked_ == 1) {
            stat_blocked_++;
        } else {
            assert(prq_length() == 0);
        }

        if(HDR_COPE(p)->ctype_ == COPE_DATA) {
	    cope_enqueue(p, false, cope_inst); //insert packet to cope-queue
  
	} else {
	    cope_enqueue(p, true, cope_inst); //insert packet to cope-queue	
	}

	// showQueue();

        /*
         * Start dequeue if idle...
         */
        if(prq_blocked_ == 0) {
	    bool empty = true;

	    // if(cope_inst->node_->nodeid() == 7) {
	    // 	cout << "-----before------" << endl;
	    // 	showQueue(cope_inst);
	    // }

            p = prq_dequeue(&empty);  // use CMU-PriQueue's dequeue method directly

	    // if(cope_inst->node_->nodeid() == 7) {
	    // 	cout << "-----after------" << endl;
	    // 	showQueue(cope_inst);
	    // 	Packet* pp = CMUPriQueue::prq_get_nexthop(6);
	    // }
	    
	    if(p) {
		// if(empty)
		//     cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
		cope_vir_table_->remove_vir_pkt(p); // synchronize virtual queue
		prq_blocked_ = 1;
		stat_send_++;
		/*
		 * Use original packet p here, since we just simulate the xor 
		 * operation and no further use for p, otherwise send_pkt should
		 * be a copy of p
		 * 
		 * The returned send packet should be original p or a encoded p.
		 *
		 * If need, packet cope will be operated inside encoding process
		 */
		Packet * send_pkt = p->copy();
		Packet * max_size_pkt = send_pkt;
		int encoded = 0;
		double timeout;
		if(HDR_COPE(p)->ctype_ != COPE_CTRL
		   && HDR_CMN(p)->next_hop() >= 0)
		    //	       && HDR_CMN(p)->next_hop() != MAC_BROADCAST)
		    encoded = cope_prq_encode(p, cope_inst, &send_pkt, &max_size_pkt);
	
		// showQueue();

		/* target_ is a member of Connector */
	
		if(encoded) {
		    //  if(cope_inst->node_->nodeid() == 5)
		    // 	 cout << "send " << HDR_CMN(send_pkt)->uid_
		    // 	      << " " << HDR_TCP(send_pkt)->seqno() << endl;

		    // switch(HDR_CMN(p)->ptype()) {
		    // case PT_TCP:
		    //   cout << CUR_TIME << " TCP: node " << cope_inst->node_->nodeid() 
		    // 	 << " cope ENCODE send down packet " 
		    // 	 << HDR_CMN(send_pkt)->cope_pkt_id()
		    // 	 << " " << HDR_CMN(send_pkt)->uid_
		    // 	 << " " << HDR_TCP(send_pkt)->seqno_
		    // 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
		    //   break;
		    // case PT_ACK:
		    //   cout << CUR_TIME << " ACK: node " << cope_inst->node_->nodeid() 
		    // 	 << " cope ENCODE send down packet " 
		    // 	 << HDR_CMN(send_pkt)->cope_pkt_id()
		    // 	 << " " << HDR_CMN(send_pkt)->uid_
		    // 	 << " " << HDR_TCP(send_pkt)->seqno_
		    // 	 << " " << HDR_TCP(send_pkt)->ackno() 
		    // 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
		    //   break;
		    // case PT_CBR:
		    //   cout << CUR_TIME <<" CBR: node " << cope_inst->node_->nodeid() 
		    // 	 << " cope ENCODE send down packet " 
		    // 	 << HDR_CMN(send_pkt)->cope_pkt_id()
		    // 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
		    // default:
		    //   cout << CUR_TIME <<" Ctrl: node " << cope_inst->node_->nodeid() 
		    // 	 << " cope ENCODE send down packet " 
		    // 	 << HDR_CMN(send_pkt)->cope_pkt_id()
		    // 	 << " to " << HDR_CMN(send_pkt)->next_hop_ << endl;
		    // }
		    // cout << "original pkt size is " << HDR_CMN(p)->cope_pkt_id() 
		    //      << " " << HDR_CMN(p)->size() << endl;
		    // cout << "max_size is " << HDR_CMN(max_size_pkt)->cope_pkt_id() 
		    //      << " "<< HDR_CMN(max_size_pkt)->size() << endl;
		    //   cout << "send out packet size is " <<HDR_CMN(send_pkt)->cope_pkt_id() 
		    // 	 << " "<< HDR_CMN(send_pkt)->size() << endl;
		    
		    timeout = cope_inst->txtime(max_size_pkt);
		  
		    CMUPriQueue::target_->recv(send_pkt, (Handler*)&prq_qh_);
		} else {
		    // switch(HDR_CMN(p)->ptype()) {
		    // case PT_TCP:
		    // 	cout << CUR_TIME << " TCP: node " << cope_inst->node_->nodeid() 
		    // 	     << " cope NATIVE send down packet " 
		    // 	     << HDR_CMN(p)->cope_pkt_id()
		    // 	     << " " << HDR_CMN(p)->uid_
		    // 	     << " " << HDR_TCP(p)->seqno_
		    // 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		    // 	break;
		    // case PT_ACK:
		    // 	cout << CUR_TIME << " ACK: node " << cope_inst->node_->nodeid() 
		    // 	     << " cope NATIVE send down packet " 
		    // 	     << HDR_CMN(p)->cope_pkt_id()
		    // 	     << " " << HDR_CMN(p)->uid_
		    // 	     << " " << HDR_TCP(p)->seqno_
		    // 	     << " " << HDR_TCP(p)->ackno() 
		    // 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		    // 	break;
		    // case PT_CBR:
		    // 	cout << CUR_TIME <<" CBR: node " << cope_inst->node_->nodeid() 
		    // 	     << " cope NATIVE send down packet " 
		    // 	     << HDR_CMN(p)->cope_pkt_id()
		    // 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		    // default:
		    // 	cout << CUR_TIME <<" Ctrl: node " << cope_inst->node_->nodeid() 
		    // 	     << " cope NATIVE send down packet " 
		    // 	     << HDR_CMN(p)->cope_pkt_id()
		    // 	     << " to " << HDR_CMN(p)->next_hop_ << endl;
		    // }

		    Packet::free(send_pkt);
		    // if(cope_inst->node_->nodeid() == 7) {
		    // 	cout << "-----after free------" << endl;
		    // 	showQueue(cope_inst);
		    // }
		    CMUPriQueue::target_->recv(p, (Handler*)&prq_qh_);
		    // if(cope_inst->node_->nodeid() == 7) {
		    // 	cout << "-----after send down------" << endl;
		    // 	showQueue(cope_inst);
		    // }
		}
		
		/* cope encode downside packet */
		if(encoded) {
		    /* send an encoded packet, should set the timer */
		    cope_inst->start_timer(send_pkt, timeout);

		} /* else send a native packet, no need for timer */
	    }
	}
#if PRIQUEUE_DEBUG > 0
	prq_validate();
#endif

    } else {  // other protocols except dsr, use PriQueue      

	if (HDR_COPE(p)->ctype_ != COPE_DATA){
	    recvHighPriority(p, cope_inst);
	    return;
	}
	
	struct hdr_cmn *ch = HDR_CMN(p);

	if(Prefer_Routing_Protocols) {
	    switch(ch->ptype()) {
	    case PT_DSR:
	    case PT_MESSAGE:
	    case PT_TORA:
	    case PT_AODV:
	    case PT_AOMDV:
		recvHighPriority(p, cope_inst);
		break;
	    default:
		recvNormalPriority(p, cope_inst);
	    }
	}
    }
}

/* return 1: send an encoded packet; return 0: send a native packet */
int COPEPriQueue::cope_prq_encode(Packet * p,
				  COPE * cope_inst, 
				  Packet ** send_pkt,
				  Packet ** max_size_pkt) {
    int encoded = 0; // native packet by default

    
    /*  if return 1, send_pkt is the encoded packet with:
     *    0.delete the encoded packet from output and virtual queue
     *    1.packet data encoded.
     *    2.xored header set.
     *    3.local seq of each encoded packet's nexthop updated
     *    4.ack of each encoded packet inserted
     *  otherwise, send_pkt = p, return 0
     */
    encoded = cope_inst->encode(p, send_pkt, max_size_pkt);
    // if(!encoded) {
    //   Packet::free(send_pkt);
    //   send_pkt = p;
    // }
    /* no matter a encoded packet or not, put append 
       acks and state report into cope header */
    if(encoded) {
 	cope_inst->append_acks(*send_pkt);
	cope_inst->append_state_report(*send_pkt);
    } else {
 	cope_inst->append_acks(p);
	cope_inst->append_state_report(p);
    }
    return encoded; 
}


/*
 * Increase the neighbor-seqnum-counter, and then call the NonAckQueue's
 * enqueue function.
 */
void COPEPriQueue::enqueue_non_ack(int nodeid, Packet* p) {
    // neighbor_seqnum_counter_ ++;
    // non_acks_->enqueue(nodeid, neighbor_seqnum_counter_, p);
}

void COPEPriQueue::recvNormalPriority(Packet* p, COPE * cope_inst) {
    double now = Scheduler::instance().clock();
    double timeout = cope_inst->txtime(p);   
    cope_enqueue(p, false, cope_inst);    
    if (!blocked_) {
	/*
	 * We're not blocked.  Get a packet and send it on.
	 * We perform an extra check because the queue
	 * might drop the packet even if it was
	 * previously empty!  (e.g., RED can do this.)
	 */
	p = deque();//DropTail's deque
	// if(length() == 0)
	//     cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
	if(p)
	    cope_vir_table_->remove_vir_pkt(p);

	if (p != 0) {
	    utilUpdate(last_change_, now, blocked_);
	    last_change_ = now;
	    blocked_ = 1;
	    /*
	     * Use original packet p here, since we just simulate the xor 
	     * operation and no further use for p, otherwise send_pkt should
	     * be a copy of p
	     */	    
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;
	    /* cope encode downside packet */
	    int encoded = cope_prq_encode(p,cope_inst,&send_pkt, &max_size_pkt);

	    // actually the downtarget_
	    PriQueue::target_->recv(send_pkt, (Handler*)&qh_);
	    if(encoded) {
		/* send an encoded packet, should set the timer */
		cope_inst->start_timer(send_pkt, timeout);
	    } /* else send a native packet, no need for timer */
	

	}
    }
}

/* 
 * call Connector::drop(), actually multi inherit can not determine one
 * specific path, so we appoint a specific path according to routing protocol
 */
void COPEPriQueue::drop(Packet * p){
    if(dsr_)
	CMUPriQueue::drop(p);
    else
	PriQueue::drop(p);
}

void COPEPriQueue::recvHighPriority(Packet* p, COPE * cope_inst) {
    double timeout = cope_inst->txtime(p);
    cope_enqueue(p, true, cope_inst);
  
    if (!blocked_) {
	/*
	 * We're not blocked.  Get a packet and send it on.
	 * We perform an extra check because the queue
	 * might drop the packet even if it was
	 * previously empty!  (e.g., RED can do this.)
	 */
	p = deque();
	// if(length() == 0)
	//     cope_inst->ctrl_pkt_timer_.start(CTRL_PKT_PEROID);
        if(p)
	    cope_vir_table_->remove_vir_pkt(p);
	if (p != 0) {
	    blocked_ = 1;
	    /*
	     * Use original packet p here, since we just simulate the xor 
	     * operation and no further use for p, otherwise send_pkt should
	     * be a copy of p
	     */
	    Packet * send_pkt = p->copy();
	    Packet * max_size_pkt = send_pkt;

	    int encoded = 0;
	    /* cope encode downside packet */
	    if(HDR_COPE(p)->ctype_ != COPE_CTRL)
		encoded = cope_prq_encode(p,cope_inst,&send_pkt, &max_size_pkt);
	    PriQueue::target_->recv(send_pkt, (Handler*)(&qh_));
	    if(encoded) {
		/* send an encoded packet, should set the timer */
		cope_inst->start_timer(send_pkt, timeout);
	    } /* else send a native packet, no need for timer */
	

	}
    }

}

void COPEPriQueue::resume(){
    if(h_cope_)
	h_cope_->handle((Event*) 0);
}

void COPEPriQueue::prq_resume(){
    if(h_cope_) {
	h_cope_->handle((Event*) 0);
    }
}

bool COPEPriQueue::isEmpty() {
    int q;
    for(q = 0; q < IFQ_MAX; q++) {
	if(prq_snd_[q].ifq_len > 0) {
	    return true;
	}
    }    
    return false;
}

Packet*
COPEPriQueue::prq_get_nexthop(nsaddr_t id)
{

    Packet * it;
    int len = 0;
    for(int q = 0; q < IFQ_MAX; q++) {
	if(prq_snd_[q].ifq_len > 0) {
	    len += prq_snd_[q].ifq_len;
	    it = prq_snd_[q].ifq_head;
	    
	    while(it != NULL) {
		// cout << setw(10) << Scheduler::instance().clock()
		//      << setw(8) << HDR_CMN(it)->uid_
		//      << setw(8) << HDR_TCP(it)->seqno()
		//      << setw(8) << HDR_CMN(it)->cope_pkt_id() 
		//      << setw(8) << HDR_CMN(it)->next_hop();
		// if(HDR_CMN(it)->ptype() == PT_ACK)
		//     cout << setw(8) << "ack" << endl;
		// else if(HDR_COPE(it)->ctype_ == COPE_RETX)
		//     cout << setw(8) << "crx" << endl;
		// else
		//     cout << endl;
		it = it->next_;
	    }
	}
    }
    cout << endl;    
    
    //  cout << "enter get" << endl;
	int q;
	Packet *p, *pprev = 0;
	struct ifqueue *ifq;

#if PRIQUEUE_DEBUG > 0
	prq_validate();
#endif
	for(q = 0; q < IFQ_MAX; q++) {
		ifq = &prq_snd_[q];
		pprev = 0;
		for(p = ifq->ifq_head; p; p = p->next_) {
			struct hdr_cmn *ch = HDR_CMN(p);
			cout << "get next " << ch->uid_ << " " << ch->cope_pkt_id() << endl;
			if(ch->next_hop() == id)
				break;
			pprev = p;
		}

	if(p) {
		if(p == ifq->ifq_head) {
			assert(pprev == 0);

			IF_DEQUEUE(ifq, p);
			/* don't increment drop counter */
#if PRIQUEUE_DEBUG > 0
			prq_validate();
#endif
			return p;
		} else {
			assert(pprev);
			pprev->next_ = p->next_;
	
			if(p == ifq->ifq_tail)
				ifq->ifq_tail = pprev;
			ifq->ifq_len--;

#if PRIQUEUE_DEBUG > 0
			prq_validate();
#endif
			p->next_ = 0;
			return p;
		}
	}
     }

	return (Packet*) 0;
}

#endif
